package com.uinnova.product.eam.service.fx.impl;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContext;
import com.uinnova.product.eam.base.local.TaskFromWorkflowContextValue;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.comm.model.es.EamDiagramRelationSys;
import com.uinnova.product.eam.config.Env;
import com.uinnova.product.eam.model.EamDiagramRelationSysCdt;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.EamDiagramRelationSysService;
import com.uinnova.product.eam.service.bm.impl.FlowModelDiagramMerge;
import com.uinnova.product.eam.service.fx.ProcessDiagramSvc;
import com.uinnova.product.eam.service.handler.PushFacadeService;
import com.uinnova.product.eam.service.impl.IamsCIRltPrivateSvc;
import com.uinnova.product.eam.service.impl.IamsCIRltSwitchSvc;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.diagram.*;
import com.uinnova.project.base.diagram.comm.model.*;
import com.uinnova.project.db.diagram.VcDiagramVersionDao;
import com.uinnova.project.db.eam.ESDiagramDao;
import com.uinnova.project.db.eam.ESDiagramLinkDao;
import com.uinnova.project.db.eam.ESDiagramNodeDao;
import com.uinnova.project.db.eam.ESDiagramSheetDao;
import com.uinnova.project.service.threadlocal.ThreadVariable;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.ESCIRltInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.query.ESRltSearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.util.ESUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProcessDiagramSvcImpl implements ProcessDiagramSvc {

    @Autowired
    ESDiagramApiClient diagramApiClient;

    @Autowired
    ESDiagramDao esDiagramDao;

    @Autowired
    ESDiagramSheetDao esDiagramSheetDao;

    @Autowired
    ESDiagramNodeDao iamsEsDiagramNodeDao;

    @Autowired
    ESDiagramLinkDao iamsEsDiagramLinkDao;

    @Autowired
    PushFacadeService pushFacadeService;

    @Autowired
    IamsCIRltSwitchSvc ciRltSwitchSvc;

    @Autowired
    FlowModelDiagramMerge flowModelDiagramMerge;

    @Autowired
    EamCategorySvc categorySvc;

    @Autowired
    VcDiagramVersionDao diagramVersionDao;

    @Autowired
    IamsCIRltPrivateSvc iamsCiRltPrivateSvc;

    @Autowired
    private EamDiagramRelationSysService diagramRelationSysService;

    @Override
    public Boolean checkDirExist(Long dirId, LibType libType) {
        EamCategory category = categorySvc.getById(dirId, libType);
        return !BinaryUtils.isEmpty(category);
    }

    @Override
    public List<ESDiagramDTO> queryDiagramInfoByIds(List<String> diagramIds) {
        List<ESDiagramDTO> esDiagramDTOS = diagramApiClient.queryFullDiagramByIds(diagramIds);
        for (ESDiagramDTO diagramDTO : esDiagramDTOS) {
            if (BinaryUtils.isEmpty(diagramDTO.getDiagram().getPrepareDiagramId())) {
                throw new BinaryException("当前视图发布缺少预制字段，请联系发布视图管理员");
            }
        }
        return esDiagramDTOS;
    }

    @Override
    public List<ESDiagramDTO> queryDiagramInfoByDirIds(List<Long> dirIds) {
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        bool.must(QueryBuilders.termsQuery("dirId", dirIds));
        bool.must(QueryBuilders.termQuery("status", 1));
        bool.must(QueryBuilders.termQuery("dataStatus", 1));
        bool.must(QueryBuilders.termQuery("historyVersionFlag", 1));
        List<ESDiagram> diagramList = esDiagramDao.getListByQuery(bool);
        List<ESDiagramDTO> esDiagramDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(diagramList)) {
            List<Long> ids = diagramList.stream().map(ESDiagram::getId).collect(Collectors.toList());
            esDiagramDTOS = diagramApiClient.queryFullDiagramByIds(ids);
            for (ESDiagramDTO diagramDTO : esDiagramDTOS) {
                if (BinaryUtils.isEmpty(diagramDTO.getDiagram().getPrepareDiagramId())) {
                    throw new BinaryException("当前视图发布缺少预制字段，请联系发布视图管理员");
                }
            }
        }
        return esDiagramDTOS;
    }

    @Override
    public Map<String, String> dealReleaseDiagram(List<ESDiagramDTO> esDiagramDTOS, String releaseDesc, Map<String, Long> diagramMap) {
        /*
         *  发布视图逻辑(视图的发布整体可以区分为初次发布和多次发布两个逻辑类型):
         *      初次发布(releaseDiagramId字段为空)：
         *          根据当前需要发布的视图copy出一张新的视图存放在资产仓库中，设置两张视图的关联关系，控制两张视图的本地版本号和发布版本号
         *      多次发布(releaseDiagramId字段为资产仓库对应的视图ID)：
         *          需要根据当前需要发布的视图查询出与之关联的资产仓库数据，将资产仓库的关联视图设置为历史版本（视图数据关联了很多表 这边先选择复制之后再删除 防止关联数据异常），版本号历史版本标识视图ID重新设置
         *          在把当前视图作为初次发布逻辑处理
         * */
        Map<String, String> localAndPublishId = new HashMap<>();   // 返回值 本地视图id对应设计库视图id

        for (ESDiagramDTO curDiagramInfo : esDiagramDTOS) {
            ESDiagramInfoDTO curDiagram = curDiagramInfo.getDiagram();
            String newEnergyId = null;
            if (BinaryUtils.isEmpty(curDiagram.getReleaseDiagramId())) {
                log.info("##########视图为初次发布，ID:【{}】", curDiagram.getDEnergy());
                curDiagram.setIsOpen(1);
                newEnergyId = this.processDiagramStep(curDiagram, releaseDesc, diagramMap.get(curDiagramInfo.getDiagram().getDEnergy()), Env.DIAGRAM_COPY_LOCAL_TO_PUBLISH);
                //初次发布维护资产库视图关联资产
                dealDiagramRelateSys(newEnergyId, curDiagram.getDEnergy());
            } else {
                // 多次发布的视图 查询仓库已发布的视图 copy一份发布的视图设置为历史版本
                log.info("##########视图为重复多次发布，ID:【{}】", curDiagram.getDEnergy());
                Long releaseEnergy = diagramApiClient.queryDiagramInfoByEnergy(curDiagram.getReleaseDiagramId());
                ThreadVariable.setSysUser(curDiagramInfo.getCreator());
                ESDiagramDTO releaseDiagramInfo = diagramApiClient.queryESDiagramInfoById(releaseEnergy, null, false);

                // 再次发布时 强制将本地视图的 releaseVersion 同步成设计库的数据
                this.synchReleaseVersionData(curDiagramInfo.getDiagram().getDEnergy(), releaseDiagramInfo.getDiagram().getReleaseVersion());

                ESDiagramInfoDTO releaseDiagram = releaseDiagramInfo.getDiagram();
                releaseDiagram.setIsOpen(null);
                String historyDiagramId = this.processDiagramStep(releaseDiagram, releaseDiagram.getReleaseDesc(), releaseDiagram.getDirId(), Env.DIAGRAM_COPY_PUBLISH_TO_PUBLISH);
                //多次发布，维护历史版本视图关联资产
                dealDiagramRelateSys(historyDiagramId, curDiagram.getDEnergy());
                // 删除上次发布记录
                this.delDiagramByIds(Collections.singletonList(releaseDiagramInfo.getDiagram().getId()).toArray(new Long[0]));

                curDiagram.setNewCopyId(releaseDiagramInfo.getDiagram().getId());
                curDiagram.setIsOpen(1);
                newEnergyId = this.processDiagramStep(curDiagram, releaseDesc, diagramMap.get(curDiagramInfo.getDiagram().getDEnergy()), Env.DIAGRAM_COPY_LOCAL_TO_PUBLISH);
                //多次发布，可能之前未维护资产库视图于关联资产关系，这里多维护一下(方法内做了判重逻辑)
                dealDiagramRelateSys(newEnergyId, curDiagram.getDEnergy());
            }
            localAndPublishId.put(curDiagram.getDEnergy(), newEnergyId);
            //如果是协作者发布，需要维护下资产创建人为发布用户
        }
        return localAndPublishId;
    }

    private void dealDiagramRelateSys(String newEnergyId, String curDiagramDEnergy) {
        //当前视图有无绑定资产
        EamDiagramRelationSys diagramRelationSys = diagramRelationSysService.getEamDiagramRelationSys(curDiagramDEnergy);
        if (diagramRelationSys == null) {
            return;
        }
        //新建视图是否已维护资产关联记录
        EamDiagramRelationSys newDiagramRelationSys = diagramRelationSysService.getEamDiagramRelationSys(newEnergyId);
        if (newDiagramRelationSys != null) {
            return;
        }
        ESDiagram newDiagram = esDiagramDao.getListByQuery(QueryBuilders.termQuery("dEnergy.keyword", newEnergyId)).get(0);
        Long dirId = 0L;
        if (newDiagram != null) {
            dirId = newDiagram.getDirId();
        }
        EamDiagramRelationSysCdt addDiagramRelationSys = new EamDiagramRelationSysCdt();
        addDiagramRelationSys.setDiagramEnergy(newEnergyId);
        addDiagramRelationSys.setDirId(dirId);
        addDiagramRelationSys.setEsSysId(diagramRelationSys.getEsSysId());
        diagramRelationSysService.saveDiagramRelationSys(addDiagramRelationSys);
    }

    @Override
    public String dealCheckOutDiagram(ESDiagramDTO publicDiagram, Long dirId, Integer actionType, String diagramName, String loginCode) {
        /*
         *  检出视图逻辑
         *      检出：
         *          1.设计空间存在与仓库关联的视图 覆盖设计空间数据
         *          2.设计空间不存在与仓库关联的视图 创建视图存放在该用户的设计空间内 两张视图存在关联关系
         *      检出另存为：
         *          1.创建视图存放在该用户的设计空间内 两张视图不存在关联关系
         * */

        List<ESDiagram> listByCdt = new ArrayList<>();
        // 根据发布视图的 ID 判断本地是否存在关联视图
        if (actionType != Env.GENERAL_DIAGRAM_COPY) {
            EamDiagramQuery eamDiagramQuery = new EamDiagramQuery();
            eamDiagramQuery.setIsOpen(0);
            eamDiagramQuery.setOwnerCodeEqual(loginCode);
            eamDiagramQuery.setReleaseDiagramId(publicDiagram.getDiagram().getDEnergy());
            eamDiagramQuery.setHistoryVersionFlag(1);
            eamDiagramQuery.setStatus(1);
            eamDiagramQuery.setDataStatus(1);
            listByCdt = esDiagramDao.getListByCdt(eamDiagramQuery);
            // 重新定义 actionType
            if (!CollectionUtils.isEmpty(listByCdt)) {
                actionType = Env.GENERAL_DIAGRAM_CHECK_OUT_COVER;
            } else {
                actionType = Env.GENERAL_DIAGRAM_CHECK_OUT;
            }
        }

        // 处理 DIAGRAM 数据
        int copyType = 3;
        ESDiagramInfoDTO curDiagram = publicDiagram.getDiagram();
        boolean dealDiagramRelateSys = false;
        if (actionType == Env.GENERAL_DIAGRAM_CHECK_OUT) {
            // 视图检出 本地不存在关联数据情况
            copyType = Env.DIAGRAM_COPY_PUBLISH_TO_LOCAL_CREATE;
            dealDiagramRelateSys = true;
        } else if (actionType == Env.GENERAL_DIAGRAM_CHECK_OUT_COVER) {
            // 视图检出 本地视图存在关联数据情况 (这里要解决关联多张视图的情况 暂时全部覆盖)
            copyType = Env.DIAGRAM_COPY_PUBLISH_TO_LOCAL_COVER;
            // 直接删除所有要覆盖的版本数据
            List<Long> relationDiagramIds = listByCdt.stream().map(ESDiagram::getId).collect(Collectors.toList());
            this.delDiagramByIds(relationDiagramIds.toArray(new Long[relationDiagramIds.size()]));
            // 指定复制数据的ID
            curDiagram.setNewCopyId(relationDiagramIds.get(0));

        } else if (actionType == Env.GENERAL_DIAGRAM_COPY) {
            // 视图检出 另存为  需要设置检出视图的新名称
            copyType = Env.DIAGRAM_COPY_PUBLISH_TO_LOCAL_NORELATION;
            curDiagram.setName(diagramName);
            dealDiagramRelateSys = true;
        } else {
            // 待补充 ***
            throw new BinaryException("视图操作参数异常，请联系开发人员！");
        }
        curDiagram.setIsOpen(0);
        curDiagram.setCreateTime(System.currentTimeMillis());
        curDiagram.setOwnerCode(loginCode);

        log.info("#############当前视图操作参数copyType：【{}】", copyType);
        String checkId = this.processDiagramStep(curDiagram, null, dirId, copyType);
        flowModelDiagramMerge.refreshDiagramData(Collections.singletonList(checkId), loginCode);
        if (dealDiagramRelateSys) {
            dealDiagramRelateSys(checkId, curDiagram.getDEnergy());
        }
        return checkId;
    }

    @Override
    public Map<String, Boolean> checkDiagramVersionByIds(List<ESDiagramDTO> esDiagramDTOS) {
        Map<String, Boolean> data = new HashMap<>();

        // 获取所有视图关联到的仓库视图数据
        List<String> releaseDiagramIds = new ArrayList<>();
        for (ESDiagramDTO diagram : esDiagramDTOS) {
            if (!BinaryUtils.isEmpty(diagram.getDiagram().getReleaseDiagramId())) {
                releaseDiagramIds.add(diagram.getDiagram().getReleaseDiagramId());
            }
        }

        if (CollectionUtils.isEmpty(releaseDiagramIds)) {
            for (ESDiagramDTO diagram : esDiagramDTOS) {
                data.put(diagram.getDiagram().getDEnergy(), false);
            }
            return data;
        }

        List<ESDiagram> releaseDiagramInfo = esDiagramDao.getListByQuery(QueryBuilders.termsQuery("dEnergy.keyword", releaseDiagramIds));
        Map<String, ESDiagram> dEnergyAndInfoMap = releaseDiagramInfo.stream().collect(Collectors.toMap(ESDiagram::getDEnergy, v -> v, (v1, v2) -> v2));

        for (ESDiagramDTO esDiagramDTO : esDiagramDTOS) {
            if (BinaryUtils.isEmpty(esDiagramDTO.getDiagram().getReleaseDiagramId())) {
                // 当前视图未发布
                data.put(esDiagramDTO.getDiagram().getDEnergy(), false);
                continue;
            }
            if (BinaryUtils.isEmpty(esDiagramDTO.getDiagram().getReleaseVersion() == 0)) {
                throw new BinaryException("当前视图对比设计库发布视图未检核出任何修改");
            }
            // 查询当前视图发布的版本号
            ESDiagram releaseDiagram = dEnergyAndInfoMap.get(esDiagramDTO.getDiagram().getReleaseDiagramId());
            if (Integer.valueOf(esDiagramDTO.getDiagram().getReleaseVersion()) < Integer.valueOf(releaseDiagram.getReleaseVersion())) {
                data.put(esDiagramDTO.getDiagram().getDEnergy(), true);     // 本地版本低于发布版本 需要检出
                continue;
            } else {
                data.put(esDiagramDTO.getDiagram().getDEnergy(), false);        // 本地版本等于发布版本 不需要检出
                continue;
            }
        }
        return data;
    }

    @Override
    public Boolean freshDiagramNode(Map<String, ESCIInfo> freshCodeMap, String loginCode) {
        Map<String, String> freshOldAndNewCodes = new HashMap<>();
        for (String privateCiCode : freshCodeMap.keySet()) {
            freshOldAndNewCodes.put(privateCiCode, freshCodeMap.get(privateCiCode).getCiCode());
        }
        log.info("##############私有库与设计库的CI的冲突数据ciCodeMap ：【{}】", JSONObject.toJSONString(freshOldAndNewCodes));

        // 查询用户设计空间所有的视图
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("isOpen", 0));
        boolQueryBuilder.must(QueryBuilders.termQuery("ownerCode.keyword", loginCode));
        List<ESDiagram> listByCdt = esDiagramDao.getListByQueryScroll(boolQueryBuilder);

        List<Long> diagramIds = new ArrayList<>();
        for (ESDiagram esDiagram : listByCdt) {
            diagramIds.add(esDiagram.getId());
        }

        // 根据私有库的code在node表中查询数据 node表中存在数据没有creator字段 不能用creator做条件 需要根据当前用户的视图id进行过滤
        List<ESDiagramNode> freshNodeList = iamsEsDiagramNodeDao.getListByQuery(QueryBuilders.termsQuery("ciCode.keyword", freshCodeMap.keySet()));
        List<ESDiagramNode> updateData = new ArrayList<>();
        freshNodeList.forEach(e -> {
            if (diagramIds.contains(e.getDiagramId().longValue())) {
                this.converNode(e, freshCodeMap);
                updateData.add(e);
            }
        });
        // 刷新视图CI节点
        if (!CollectionUtils.isEmpty(updateData)) {
            iamsEsDiagramNodeDao.saveOrUpdateBatch(updateData);
        }

        // 关系Link 数据 刷新
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        for (String ciCode : freshCodeMap.keySet()) {
            bool.should(QueryBuilders.wildcardQuery("uniqueCode.keyword","*" + ciCode + "*"));
        }
        List<ESDiagramLink> freshLinkList = iamsEsDiagramLinkDao.getListByQuery(bool);

        Set<String> uniqueCodes = new HashSet<>();
        for (ESDiagramLink esDiagramLink : freshLinkList) {
            uniqueCodes.add(esDiagramLink.getUniqueCode());
        }
        if (CollectionUtils.isEmpty(uniqueCodes)) {
            log.info("##############私有库无关系的冲突数据");
            pushFacadeService.processCatalog(freshOldAndNewCodes, loginCode);
            return true;
        }
        log.info("##############私有库关系的冲突数据uniqueCodes ：【{}】", JSONObject.toJSONString(uniqueCodes));
        Map<String, String> freshLinkCodeMap = new HashMap<>();
        // 根据link节点的 uniqueCode 获取用户的冲突rlt数据 并刷新

        ESRltSearchBean esRltSearchBean = new ESRltSearchBean();
        esRltSearchBean.setOwnerCode(loginCode);
        esRltSearchBean.setRltUniqueCodes(uniqueCodes);
        esRltSearchBean.setPageNum(1);
        esRltSearchBean.setPageSize(uniqueCodes.size());
        Page<ESCIRltInfo> esciRltInfoPage1 = ciRltSwitchSvc.searchRlt(esRltSearchBean, LibType.PRIVATE);

        List<ESCIRltInfo> privateRltInfos = esciRltInfoPage1.getData();
        Set<String> freshCodeList = freshCodeMap.keySet();
        for (ESCIRltInfo privateRlt : privateRltInfos) {
            if (freshCodeList.contains(privateRlt.getTargetCiCode()) || freshCodeList.contains(privateRlt.getSourceCiCode())) {
                // 记录当前关系 在设计库修改 并更新 link 表 逐条更新
                String oldPrivateUniqueCode = privateRlt.getUniqueCode();
                String newPrivateUniqueCode = oldPrivateUniqueCode;
                if (freshCodeList.contains(privateRlt.getTargetCiCode())) {
                    // 目标端数据需要替换
                    newPrivateUniqueCode = newPrivateUniqueCode.replace(privateRlt.getTargetCiCode(), freshCodeMap.get(privateRlt.getTargetCiCode()).getCiCode());
                }
                if (freshCodeList.contains(privateRlt.getSourceCiCode())) {
                    // 源端数据需要替换
                    newPrivateUniqueCode = newPrivateUniqueCode.replace(privateRlt.getSourceCiCode(), freshCodeMap.get(privateRlt.getSourceCiCode()).getCiCode());
                }
                freshLinkCodeMap.put(oldPrivateUniqueCode, newPrivateUniqueCode);
            }
        }
        log.info("##############私有库与设计库关系的冲突数据uniqueCodeMap ：【{}】", JSONObject.toJSONString(freshLinkCodeMap));

        Map<String,String> syncCodeMap = new HashMap<>();
        for (String privateCiCode : freshCodeMap.keySet()) {
            syncCodeMap.put(privateCiCode, freshCodeMap.get(privateCiCode).getCiCode());
        }
        iamsCiRltPrivateSvc.replaceCiCodeInCiRltList(privateRltInfos, syncCodeMap);
        // iamsCiRltPrivateSvc.bindBatchCiRlt(newRltList, loginCode);

        List<ESDiagramLink> updateLinks = new ArrayList<>();
        freshLinkList.forEach(e -> {
            if (diagramIds.contains(e.getDiagramId().longValue())) {
                this.converLink(e, freshLinkCodeMap);
                updateLinks.add(e);
            }
        });

        // 批量刷新关系节点
        if (!CollectionUtils.isEmpty(updateLinks)) {
            iamsEsDiagramLinkDao.saveOrUpdateBatch(freshLinkList);
        }

        // 文件目录刷新
        pushFacadeService.processCatalog(freshOldAndNewCodes, loginCode);
        return true;
    }

    /**
     *  资产内视图复制 并调整数据
     * @param curDiagram
     * @param releaseDesc
     * @param dirId
     * @param copyType
     * @return
     */
    private String processDiagramStep(ESDiagramInfoDTO curDiagram, String releaseDesc, Long dirId, int copyType) {
        ESDiagramMoveCdt esDiagramMoveCdt = this.transDiagramInfo(curDiagram, releaseDesc, dirId);
        String newEnergyId = diagramApiClient.copyDiagramById(esDiagramMoveCdt);
        ESDiagram newCopyDiagram = esDiagramDao.getListByQuery(QueryBuilders.termQuery("dEnergy.keyword", newEnergyId)).get(0);

        List<ESDiagram> updateData = new ArrayList<>();
        switch (copyType) {
            case 1 : {
                updateData = this.copyLocalToPublish(newCopyDiagram, curDiagram.getId(), newEnergyId);
                break;
            }
            case 2 : {
                updateData = this.copyPublishToPublish(newCopyDiagram, curDiagram.getReleaseDiagramId());
                break;
            }
            case 3 : {
                updateData = this.copyPublishToLocalCreate(newCopyDiagram, curDiagram);
                break;
            }
            case 4 : {
                updateData = this.copyPublishToLocalCover(newCopyDiagram, curDiagram);
                break;
            }
            case 5 : {
                updateData = this.copyPublishToLocalNoRelation(newCopyDiagram);
                break;
            }
            default: {
                break;
            }
        }
        esDiagramDao.saveOrUpdateBatch(updateData);
//        if (newCopyDiagram.getIsOpen() == 0) {
//            creatOrUpdateVersionInfo(newCopyDiagram.getId(), SysUtil.getCurrentUserInfo());
//        }
        return newEnergyId;
    }

    /**
     *  检出视图更新历史版本关联表信息
     * @param diagramId
     * @param curentUser
     */
    private void creatOrUpdateVersionInfo(Long diagramId, SysUser curentUser) {
        VcDiagramVersion vcDiagramVersion = diagramVersionDao.selectById(diagramId);
        if (BinaryUtils.isEmpty(vcDiagramVersion)) {
            VcDiagramVersion version = new VcDiagramVersion();
            version.setId(diagramId);
            version.setStatus(1);
            version.setDiagramId(diagramId);
            version.setDomainId(1L);
            version.setVersionTime(BinaryUtils.getNumberDateTime());
            version.setCreator(curentUser.getUserName() + "[" + curentUser.getLoginCode() + "]");
            diagramVersionDao.insertAsync(version, curentUser);
            log.info("#########初始化创建历史版本成功");
        } else {
            diagramVersionDao.updateByIdAsync(vcDiagramVersion, diagramId, curentUser.getLoginCode());
            log.info("#########检出更新历史版本主视图修改时间成功");
        }
    }

    private void synchReleaseVersionData(String id, Integer releaseVersion) {
        // 刷新releaseVersion 同步设计库
        StringBuffer script = new StringBuffer(1000);
        script.append("ctx._source.releaseVersion=params.releaseVersion;");
        Map<String,Object> params = new HashMap<>();
        params.put("releaseVersion", releaseVersion);
        esDiagramDao.updateByQuery(QueryBuilders.termQuery("dEnergy.keyword", id), script.toString(), true, params);
    }

    /**
     *  转化视图数据格式
     * @param diagram
     * @param releaseDesc
     * @param dirId
     * @return
     */
    private ESDiagramMoveCdt transDiagramInfo(ESDiagramInfoDTO diagram, String releaseDesc, Long dirId) {
        ESDiagramMoveCdt esDiagramMoveCdt = new ESDiagramMoveCdt();
        esDiagramMoveCdt.setNewName(diagram.getName());
        esDiagramMoveCdt.setNewDirId(dirId);
        esDiagramMoveCdt.setDiagramId(diagram.getDEnergy());
        esDiagramMoveCdt.setViewType(diagram.getViewType());
        esDiagramMoveCdt.setIsOpen(diagram.getIsOpen());
        esDiagramMoveCdt.setReleaseDiagramId(diagram.getReleaseDiagramId());
        esDiagramMoveCdt.setReleaseDesc(releaseDesc);
        esDiagramMoveCdt.setCreateHistory(false);
        esDiagramMoveCdt.setCreateHistoryVersion(false);   // 选择不创建历史版本
        esDiagramMoveCdt.setCreateTime(diagram.getCreateTime());
        esDiagramMoveCdt.setOwnerCode(diagram.getOwnerCode());
        // newCopyId 指定复制出的新视图的ID 空值新视图的ID随机生成
        if (!BinaryUtils.isEmpty(diagram.getNewCopyId())) {
            esDiagramMoveCdt.setCopyDiagramId(diagram.getNewCopyId());
        }
        return esDiagramMoveCdt;
    }

    /**
     *  根据视图ID删除视图及关联数据
     * @param diagramIds
     * @return
     */
    private String delDiagramByIds (Long[] diagramIds) {
        StringBuilder strBuilder = new StringBuilder("删除视图记录：");
        if (BinaryUtils.isEmpty(diagramIds)) {
            throw new BinaryException("视图ids不能为空");
        }
        // ESDiagram esDiagram = esDiagramDao.getById(diagramId);
        List<ESDiagram> esDiagrams = esDiagramDao.getListByQuery(QueryBuilders.termsQuery("id", diagramIds));
        //1.根据视图id集合查询视图数据
        EamDiagramQuery query = new EamDiagramQuery();
        query.setIds(diagramIds);
        Integer deleteDiagramCount = esDiagramDao.deleteByQuery(ESUtil.cdtToBuilder(query), true);
        strBuilder.append("视图是否删除成功：").append(deleteDiagramCount);
        //2.根据视图id集合查询其包含的所有sheet数据
        ESDiagramSheetQuery sheetQuery = new ESDiagramSheetQuery();
        sheetQuery.setDiagramIds(diagramIds);
        Integer deleteSheetCount = esDiagramSheetDao.deleteByQuery(ESUtil.cdtToBuilder(sheetQuery), true);
        strBuilder.append("sheet是否删除成功：").append(deleteSheetCount);
        //3.查询所有的node节点，将其按照diagramId和sheetId进行分组
        ESDiagramNodeQuery nodeQuery = new ESDiagramNodeQuery();
        nodeQuery.setDiagramIds(diagramIds);
        Integer deleteNodeCount = iamsEsDiagramNodeDao.deleteByQuery(ESUtil.cdtToBuilder(sheetQuery), true);
        strBuilder.append("node是否删除成功：").append(deleteNodeCount);
        //4.查询所有的link节点，将其按照diagramId和sheetId进行分组
        ESDiagramLinkQuery linkQuery = new ESDiagramLinkQuery();
        linkQuery.setDiagramIds(diagramIds);
        Integer deleteLinkCount = iamsEsDiagramLinkDao.deleteByQuery(ESUtil.cdtToBuilder(sheetQuery), true);
        strBuilder.append("link是否删除成功：").append(deleteLinkCount);
        return strBuilder.toString();
    }

    /**
     *  copy视图 本地 -》 仓库
     * @param publishDiagram
     * @param curDiagramId
     * @param newEnergyId
     * @return
     */
    private List<ESDiagram> copyLocalToPublish(ESDiagram publishDiagram, Long curDiagramId, String newEnergyId) {
        List<ESDiagram> updateData = new ArrayList<>();
        // 本地视图字段的调整
//        // 转化的有点问题 直接查一下吧
//        ESDiagram localESDiagram = JSONObject.parseObject(JSONObject.toJSONString(curDiagram), ESDiagram.class);
//        log.info("#########转化的：【{}】", JSONObject.toJSONString(localESDiagram));
        ESDiagram localESDiagram = esDiagramDao.getById(curDiagramId);
        // 本地视图绑定releaseDiagram 为资产仓库视图的加密ID
        localESDiagram.setReleaseDiagramId(newEnergyId);
        // 本地视图localVersion 归零
        localESDiagram.setLocalVersion(0);
        // 本地视图的flowfStatus设为0
        localESDiagram.setFlowStatus(0);
        // 本地视图releaseVersion + 1
        localESDiagram.setReleaseVersion(!BinaryUtils.isEmpty(localESDiagram.getReleaseVersion()) ? localESDiagram.getReleaseVersion() + 1 : 1);
        // esDiagramDao.saveOrUpdate(localESDiagram);
        updateData.add(localESDiagram);

        // 资产仓库视图字段的调整
        // 资产仓库视图绑定releaseDiagram 为本身的加密ID
        publishDiagram.setReleaseDiagramId(newEnergyId);
        // 仓库视图releaseVersion + 1
        publishDiagram.setReleaseVersion(!BinaryUtils.isEmpty(publishDiagram.getReleaseVersion()) ? publishDiagram.getReleaseVersion() + 1 : 1);
        TaskFromWorkflowContextValue contextValue = TaskFromWorkflowContext.getContext();
        //来自工作流且流程发起人非视图创建人时，资产视图创建者为发起者
        if (contextValue != null && contextValue.getFromWorkflow()
                && !contextValue.getStartUserLoginCode().equals(localESDiagram.getCreator())) {
            publishDiagram.setCreator(contextValue.getStartUserLoginCode());
            publishDiagram.setOwnerCode(contextValue.getStartUserLoginCode());
        }
        updateData.add(publishDiagram);
        return updateData;
    }

    /**
     *  copy视图 仓库 -》 仓库
     * @param publishDiagram
     * @param releaseDiagramId
     * @return
     */
    private List<ESDiagram> copyPublishToPublish(ESDiagram publishDiagram, String releaseDiagramId) {
        List<ESDiagram> updateData = new ArrayList<>();
        // 资产仓库视图历史版本标识设置为0
        publishDiagram.setHistoryVersionFlag(0);
        // 资产仓库视图发布关联字段设置
        publishDiagram.setReleaseDiagramId(releaseDiagramId);
        updateData.add(publishDiagram);
        return updateData;
    }

    /**
     *  copy视图 仓库 -》 本地 （新建）
     * @return
     */
    private List<ESDiagram> copyPublishToLocalCreate(ESDiagram newCopyDiagram, ESDiagramInfoDTO curDiagram) {
        List<ESDiagram> updateData = new ArrayList<>();
        // 新生成的视图关联字段
        newCopyDiagram.setReleaseDiagramId(curDiagram.getReleaseDiagramId());
        // 本地视图的版本号同步成仓库视图的版本号
        newCopyDiagram.setReleaseVersion(curDiagram.getReleaseVersion());
        newCopyDiagram.setLocalVersion(0);
        updateData.add(newCopyDiagram);
        this.creatRltLocalVersion(newCopyDiagram);
        return updateData;
    }

    /**
     *  copy视图 仓库 —》 本地 （覆盖）
     * @return
     */
    private List<ESDiagram> copyPublishToLocalCover(ESDiagram newCopyDiagram, ESDiagramInfoDTO curDiagram) {
        List<ESDiagram> updateData = new ArrayList<>();
        // 新生成的视图关联字段
        newCopyDiagram.setReleaseDiagramId(curDiagram.getReleaseDiagramId());
        // 本地视图的版本号同步成仓库视图的版本号
        newCopyDiagram.setReleaseVersion(curDiagram.getReleaseVersion());
        newCopyDiagram.setLocalVersion(0);
        updateData.add(newCopyDiagram);
        return updateData;
    }

    /**
     *  copy视图 仓库 —》 本地 (无关联创建)
     * @return
     */
    private List<ESDiagram> copyPublishToLocalNoRelation(ESDiagram newCopyDiagram) {
        List<ESDiagram> updateData = new ArrayList<>();
        // 新视图业务主键字段关联
        newCopyDiagram.setPrepareDiagramId(SecureUtil.md5(String.valueOf(newCopyDiagram.getId())).substring(8, 24));
        // 新视图版本号归0
        newCopyDiagram.setLocalVersion(0);
        newCopyDiagram.setReleaseVersion(0);
        updateData.add(newCopyDiagram);
        this.creatRltLocalVersion(newCopyDiagram);
        return updateData;
    }

    /**
     * node节点刷新
     *
     * @param e
     */
    private void converNode(ESDiagramNode e, Map<String, ESCIInfo> freshCodeMap) {
        final String code = freshCodeMap.get(e.getCiCode()).getCiCode();
        String nodeStr = e.getNodeJson();
        JSONObject nodeJson = JSON.parseObject(nodeStr);
        if (!BinaryUtils.isEmpty(nodeJson)) {
            if (!BinaryUtils.isEmpty(nodeJson.get("ciCode"))) {
                nodeJson.put("ciCode", code);
            }
        }
        e.setNodeJson(nodeJson.toJSONString());
        e.setCiCode(code);
    }

    /**
     * link节点刷新
     *
     * @param e
     */
    private void converLink(ESDiagramLink e, Map<String, String> freshCodeMap) {
        final String rltCode = freshCodeMap.get(e.getUniqueCode());
        String linkStr = e.getLinkJson();
        JSONObject linkJson = JSON.parseObject(linkStr);
        if (!BinaryUtils.isEmpty(linkJson)) {
            if (!BinaryUtils.isEmpty(linkJson.get("rltCode"))) {
                linkJson.put("rltCode", rltCode);
            }
        }
        e.setLinkJson(linkJson.toJSONString());
        e.setUniqueCode(rltCode);
    }

    /**
     *  创建视图本地版本关联数据
     * @param esDiagram
     */
    private void creatRltLocalVersion(ESDiagram esDiagram) {
        VcDiagramVersion dto = new VcDiagramVersion();
        dto.setId(esDiagram.getId());
        dto.setDiagramId(esDiagram.getId());
        dto.setVersionTime(esDiagram.getCreateTime());
        dto.setStatus(1);
        dto.setDomainId(1L);
        dto.setDataStatus(1);
        dto.setCreator(esDiagram.getOwnerCode() + "[" + esDiagram.getOwnerCode() + "]");
        dto.setModifier(esDiagram.getOwnerCode());
        diagramVersionDao.insert(dto);
    }
}
